package notify

import (
	"encoding/json"
	"github.com/pkg/errors"
	"go.uber.org/zap"
	"myCloud/config"
	"myCloud/constant"
	"myCloud/logsvr"
	"nanomsg.org/go-mangos"
	"nanomsg.org/go-mangos/protocol/pub"
	"nanomsg.org/go-mangos/transport/inproc"
	"strings"
)

type SysBus struct {
	sock mangos.Socket
	path string
}

var (
	glSysBus *SysBus
	logger   = logsvr.GetLogger("notify")
)

/*
SvrInit 消息队列服务
*/
func SvrInit(cfg *config.MQConfig) {
	var err error
	glSysBus, err = NewMQ(cfg.Path)
	if err != nil {
		logger.Warnw("init mq service failed.", zap.Error(err))
		return
	}
}

func NewMQ(path string) (*SysBus, error) {
	sock, err := pub.NewSocket()
	if err != nil {
		return nil, errors.Wrap(err, "new publish socket failed.")
	}

	//sock.AddTransport(ipc.NewTransport())
	//sock.AddTransport(tcp.NewTransport())
	sock.AddTransport(inproc.NewTransport())

	err = sock.Listen(path)
	if err != nil {
		return nil, errors.Wrap(err, "listen mq failed.")
	}
	logger.Debugf("listen mq service at %s", path)

	return &SysBus{
		sock: sock,
		path: path,
	}, nil
}

/*
简化协议
key \x00 body
*/
func (m *SysBus) commonPublish(topic string, body []byte) error {
	if strings.IndexByte(topic, 0) != -1 {
		return errors.New("topic must not contain \\x00")
	}

	out := make([]byte, 0)
	out = append(out, []byte(topic)...)
	out = append(out, 0)
	out = append(out, body...)

	return m.sock.Send(out)
}

type eventFrame struct {
	EventID int `json:"event_id"`
}

func handleNotifyError(err error) {
	if err != nil {
		logger.Errorw("send publish message failed.", zap.Error(err))
	}
}

func FileUploadFinished(fileID int) {
	notifyEvent(constant.NotifyFileUploadFinished, fileID)
}

func DeviceOffline(devID int) {
	notifyEvent(constant.NotifyDeviceOffline, devID)
}

func notifyEvent(topic string, devID int) {
	var req = eventFrame{
		EventID: devID,
	}
	body, err := json.Marshal(&req)
	if err != nil {
		logger.Errorw("json marshal device online frame failed.", zap.Error(err))
		return
	}

	err = glSysBus.commonPublish(topic, body)
	handleNotifyError(err)
}

func NewUserRegistered(userID uint) {
	var req = make(map[string]uint)
	req["user_id"] = userID

	body, err := json.Marshal(&req)
	if err != nil {
		logger.Errorw("json marshal device online frame failed.", zap.Error(err))
		return
	}

	err = glSysBus.commonPublish(constant.NotifyUserRegistered, body)
	handleNotifyError(err)
}
